home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 031a / adg_4_6.zip / SPIN.C < prev    next >
C/C++ Source or Header  |  1991-02-21  |  9KB  |  285 lines

  1. /****************************************************************************
  2. Module name: Spin.C
  3. Programmer : Jeffrey M. Richter.
  4. *****************************************************************************/
  5.  
  6. #include "..\nowindws.h"
  7. #define  OEMRESOURCE
  8. #undef   NOCOLOR
  9. #undef   NOCTLMGR
  10. #undef   NOGDI
  11. #undef   NOKERNEL
  12. #undef   NOLSTRING
  13. #undef   NOMEMMGR
  14. #undef   NORASTEROPS
  15. #undef   NOUSER
  16. #undef   NOVIRTUALKEYCODES
  17. #undef   NOWINMESSAGES
  18. #undef   NOWINOFFSETS
  19. #undef   NOWINSTYLES
  20. #include <windows.h>
  21.  
  22. #include "spin.h"
  23.  
  24. #define CBWNDEXTRA            (8)
  25. #define GWL_RANGE             (0)
  26. #define GWW_CRNTVALUE         (4)
  27. #define GWW_TRIANGLEDOWN      (6)
  28.  
  29. #define SPNM_SCROLLVALUE      (WM_USER + 500)
  30.  
  31.    // Time delay between scrolling events in milliseconds.
  32. #define TIME_DELAY            (150) 
  33.  
  34. typedef enum { TD_NONE, TD_UP, TD_DOWN } TRIANGLEDOWN;
  35.  
  36. HANDLE _hInstance = NULL;
  37. char _szControlName[] = "Spin";
  38.  
  39. static BOOL NEAR PASCAL RegisterControlClass (HANDLE hInstance);
  40. LONG FAR PASCAL SpinWndFn (HWND hWnd, WORD wMsg, WORD wParam, LONG lParam);
  41.  
  42. /********* Window's Dynamic-Link Library Initialization Routines ***********/
  43.  
  44. BOOL FAR PASCAL LibMain (HANDLE hModule, WORD wDataSeg, WORD wHeapSize, LPSTR lpszCmdLine) {
  45.    BOOL fOk;
  46.    _hInstance = hModule;
  47.    if (wHeapSize != 0) UnlockData(0);  // Let data segment move
  48.    fOk = RegisterControlClass(hModule);
  49.    return(fOk);   // return TRUE if initialization is successful
  50. }
  51.  
  52.  
  53. int FAR PASCAL WEP (int nSystemExit) {
  54.  
  55.    switch (nSystemExit) {
  56.       case WEP_SYSTEM_EXIT:   // System is shutting down.
  57.          break;
  58.       case WEP_FREE_DLL:      // Usage count is zero (0)
  59.          break;
  60.    }
  61.    UnregisterClass(_szControlName, _hInstance);
  62.    return(1);                 // WEP function successful.
  63. }
  64.  
  65.  
  66. static BOOL NEAR PASCAL RegisterControlClass (HANDLE hInstance) {
  67.    WNDCLASS wc;
  68.    wc.style         = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
  69.    wc.lpfnWndProc   = SpinWndFn;
  70.    wc.cbClsExtra    = 0;
  71.    wc.cbWndExtra    = CBWNDEXTRA;
  72.    wc.hInstance     = hInstance;
  73.    wc.hIcon         = NULL;
  74.    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  75.    wc.hbrBackground = COLOR_BTNFACE + 1;
  76.    wc.lpszMenuName  = NULL;
  77.    wc.lpszClassName = _szControlName;
  78.    return(RegisterClass(&wc));
  79. }
  80.  
  81. static LONG NEAR PASCAL NotifyParent (HWND hWnd, WORD wNotifyCode) {
  82.    LONG lResult;
  83.    lResult = SendMessage(GetParent(hWnd), WM_COMMAND,
  84.                GetWindowWord(hWnd, GWW_ID),
  85.                MAKELONG(hWnd, wNotifyCode));
  86.    return(lResult);
  87. }
  88.  
  89. LONG FAR PASCAL SpinWndFn (HWND hWnd, WORD wMsg, WORD wParam, LONG lParam) {
  90.    LONG lResult = 0;
  91.    HDC hDC;
  92.    POINT pt;
  93.    RECT rc;
  94.    PAINTSTRUCT ps;
  95.    int nCrntVal, nNewVal, x, y;
  96.    TRIANGLEDOWN TriangleDown, OldTriangleDown;
  97.    DWORD dwTime, dwRange;
  98.    BOOL fWrap;
  99.  
  100.    switch (wMsg) {
  101.       case WM_GETDLGCODE:
  102.          lResult = DLGC_STATIC;
  103.          break;
  104.  
  105.       case WM_CREATE:   // lParam == &CreateStruct
  106.          SendMessage(hWnd, SPNM_SETRANGE, 0, MAKELONG(0, 0));
  107.          SendMessage(hWnd, SPNM_SETCRNTVALUE, 0, 0);
  108.          break;
  109.  
  110.       case WM_PAINT:
  111.          // Calling BeginPaint sends a WM_ERASEBKGND message.  Because that
  112.          // message is not trapped, DefWindowProc uses the system color
  113.          // COLOR_BTNFACE because it was specified in the hbrBackground
  114.          // member of the WNDCLASS structure when this class was registered.
  115.          hDC = BeginPaint(hWnd, &ps);
  116.  
  117.          GetClientRect(hWnd, &rc);
  118.          x = rc.right / 2;
  119.          y = rc.bottom / 2;
  120.  
  121.             // Draw middle separator bar
  122.          MoveTo(hDC, 0, y);
  123.          LineTo(hDC, rc.right, y);
  124.  
  125.  
  126.          // Whenever a DC is retrieved, it is created with a WHITE_BRUSH
  127.          // by default, we must change this to a BLACK_BRUSH so that we
  128.          // can fill the triangles.
  129.          SelectObject(hDC, GetStockObject(BLACK_BRUSH));
  130.  
  131.             // Draw top triangle & fill it in
  132.          MoveTo(hDC, x, 2);
  133.          LineTo(hDC, rc.right - 2, y - 2);
  134.          LineTo(hDC, 2, y - 2);
  135.          LineTo(hDC, x, 2);
  136.          FloodFill(hDC, x, y - 3, RGB(0, 0, 0));
  137.  
  138.             // Draw bottom triangle & fill it in
  139.          MoveTo(hDC, 2, y + 2);
  140.          LineTo(hDC, rc.right - 2, y + 2);
  141.          LineTo(hDC, x, rc.bottom - 2);
  142.          LineTo(hDC, 2, y + 2);
  143.          FloodFill(hDC, x, y + 3, RGB(0, 0, 0));
  144.          EndPaint(hWnd, &ps);
  145.          break;
  146.  
  147.  
  148.       case WM_LBUTTONDOWN:
  149.          // Get coordinates for the Spin Button's window.
  150.          GetClientRect(hWnd, &rc);
  151.  
  152.  
  153.          if ((int) HIWORD(lParam) < rc.bottom / 2) {  // Up arrow
  154.             TriangleDown = TD_UP;
  155.             // Change coordinates so rectangle includes only the top-half 
  156.             // of the window.
  157.             rc.bottom /= 2;
  158.          } else {
  159.             TriangleDown = TD_DOWN;
  160.  
  161.             // Change coordinates so rectangle includes only the bottom-half 
  162.             // of the window.
  163.             rc.top = rc.bottom / 2;
  164.          }
  165.  
  166.          // Save which triangle the mouse was clicked over.
  167.          SetWindowWord(hWnd, GWW_TRIANGLEDOWN, TriangleDown);
  168.  
  169.          // Invert the top or bottom half of the window where the 
  170.          // mouse was clicked.
  171.          hDC = GetDC(hWnd);
  172.          InvertRect(hDC, &rc);
  173.          ReleaseDC(hWnd, hDC);
  174.  
  175.          SetCapture(hWnd);
  176.  
  177.          // Subtract TIME_DELAY so that action is performed at least once.
  178.          dwTime = GetTickCount() - TIME_DELAY;
  179.  
  180.          do {
  181.             // If TIME_DELAY hasn't passed yet, test loop condition.
  182.             if (dwTime + TIME_DELAY > GetTickCount())
  183.                continue;
  184.  
  185.             // Time delay has passed, scroll value in Spin Button.
  186.             SendMessage(hWnd, SPNM_SCROLLVALUE, 0, 0l);
  187.  
  188.             // Get last time when scroll occurred.
  189.             dwTime = GetTickCount();
  190.  
  191.             // Check if left mouse button is still down.
  192.          } while (GetAsyncKeyState(VK_LBUTTON) & 0x8000);
  193.  
  194.          ReleaseCapture();
  195.  
  196.          // Invalidate the entire window.  This will force Windows to send
  197.          // a WM_PAINT message restoring the window to its original colors.
  198.          InvalidateRect(hWnd, NULL, TRUE);
  199.          break;
  200.  
  201.       case SPNM_SCROLLVALUE:
  202.          // Get the location of the mouse.
  203.          GetCursorPos(&pt);
  204.  
  205.          // Convert the point from screen coordinates to client coordinates.
  206.          ScreenToClient(hWnd, &pt);
  207.  
  208.          // If the point is NOT is Spin's client area, nothing to do.
  209.          GetClientRect(hWnd, &rc);
  210.          if (!PtInRect(&rc, pt)) break;
  211.  
  212.          // Get the Spin Button's current value and range, 
  213.          nNewVal = (int) SendMessage(hWnd, SPNM_GETCRNTVALUE, 0, 0l);
  214.          nCrntVal = nNewVal;
  215.          dwRange = SendMessage(hWnd, SPNM_GETRANGE, 0, 0l);
  216.  
  217.          // Get Spin Button's styles and test if the "wrap" flag is set.
  218.          fWrap = (BOOL) (GetWindowLong(hWnd, GWL_STYLE) & SPNS_WRAP);
  219.  
  220.          // Determine whether the up- or down- triangle was selected.
  221.          OldTriangleDown = GetWindowWord(hWnd, GWW_TRIANGLEDOWN);
  222.  
  223.          // Determine whether the mouse is now over the up- or down- triangle.
  224.          TriangleDown = (pt.y < rc.bottom / 2) ? TD_UP : TD_DOWN;
  225.  
  226.          // If the user has switched triangles, invert the entire rectangle.
  227.          // This restores the half that was inverted in the WM_LBUTTONDOWN
  228.          // message and inverts the new half.
  229.          if (OldTriangleDown != TriangleDown) {
  230.             hDC = GetDC(hWnd);
  231.             InvertRect(hDC, &rc);
  232.             ReleaseDC(hWnd, hDC);
  233.          }
  234.  
  235.          if (TriangleDown == TD_UP) {
  236.             // If value is not at top of range, increment it.
  237.             if ((int) HIWORD(dwRange) > nCrntVal) nNewVal++;
  238.             else {
  239.                // If value at top of range and the "wrap" flag is set, 
  240.                // set the value to the bottom of the range.
  241.                if (fWrap) nNewVal = (int) LOWORD(dwRange);
  242.             }
  243.  
  244.          } else {
  245.             // If value is not at bottom of range, decrement it.
  246.             if ((int) LOWORD(dwRange) < nCrntVal) nNewVal--;
  247.             else {
  248.                // If value at bottom of range and the "wrap" flag is set, 
  249.                // set the value to the top of the range.
  250.                if (fWrap) nNewVal = (int) HIWORD(dwRange);
  251.             }
  252.          }
  253.  
  254.          // If the value has been changed, set the new value.
  255.          if (nNewVal != nCrntVal)
  256.             SendMessage(hWnd, SPNM_SETCRNTVALUE, nNewVal, 0l);
  257.  
  258.          // Set the new triangle that is down for the next call to here.
  259.          SetWindowWord(hWnd, GWW_TRIANGLEDOWN, TriangleDown);
  260.          break;
  261.  
  262.       case SPNM_SETRANGE:
  263.          SetWindowLong(hWnd, GWL_RANGE, lParam);
  264.          break;
  265.  
  266.       case SPNM_GETRANGE:
  267.          lResult = GetWindowLong(hWnd, GWL_RANGE);
  268.          break;
  269.  
  270.       case SPNM_SETCRNTVALUE:
  271.          SetWindowWord(hWnd, GWW_CRNTVALUE, wParam);
  272.          NotifyParent(hWnd, SPNN_VALUECHANGE);
  273.          break;
  274.  
  275.       case SPNM_GETCRNTVALUE:
  276.          lResult = (LONG) GetWindowWord(hWnd, GWW_CRNTVALUE);
  277.          break;
  278.  
  279.       default:
  280.          lResult = DefWindowProc(hWnd, wMsg, wParam, lParam);
  281.          break;
  282.    }
  283.    return(lResult);
  284. }
  285.